﻿#region Librerias

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

#endregion

 
namespace ESF.General
{
	public static class PredicateBuilder
	{
	  public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
	  public static Expression<Func<T, bool>> False<T> () { return f => false; }
 
	  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> pThisExpression,
														  Expression<Func<T, bool>> pExpA)
	  {
		return Or<T> (pThisExpression, pExpA, true);
	  }
 
	  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> pThisExpression,
														   Expression<Func<T, bool>> pExpA)
	  {
		return And<T> (pThisExpression, pExpA, true);
	  }


	  public static Expression<Func<T, bool>> OrIfNotNull<T> (this Expression<Func<T, bool>> pThisExpression,
														  Expression<Func<T, bool>> pExpA, object pValue)
	  {
		if (pValue != null)
		{
			return Or<T> (pThisExpression, pExpA, true);
		}
		else
		{
			return pThisExpression;
		}
	  }


	  public static Expression<Func<T, bool>> AndIfNotNull<T> (this Expression<Func<T, bool>> pThisExpression,
														   Expression<Func<T, bool>> pExpA, object pValue)
	  {
			if (pValue != null)
			{
				return And<T> (pThisExpression, pExpA, true);
			}
			else
			{
				return pThisExpression;
			}
	  }


	  public static Expression<Func<T, bool>> OrIfNotNullOrEmpty<T> (this Expression<Func<T, bool>> pThisExpression,
														  Expression<Func<T, bool>> pExpA, string pValue)
	  {
		if (!TextHelper.IsEmpty (pValue))
		{
			return Or<T> (pThisExpression, pExpA, true);
		}
		else
		{
			return pThisExpression;
		}
	  }
 
	  public static Expression<Func<T, bool>> AndIfNotNullOrEmpty<T> (this Expression<Func<T, bool>> pThisExpression,
														   Expression<Func<T, bool>> pExpA, string pValue)
	  {
			if (!TextHelper.IsEmpty (pValue))
			{
				return And<T> (pThisExpression, pExpA, true);
			}
			else
			{
				return pThisExpression;
			}
	  }


	  public static Expression<Func<T, bool>> AndIfNotNullOrEmpty<T,O>(this Expression<Func<T, bool>> pThisExpression,
														   Expression<Func<T, bool>> pExpA, params O [] pValues)
	  {
		  if (!DataHelper.IsEmpty(pValues))
		  {
			  return And<T>(pThisExpression, pExpA, true);
		  }
		  else
		  {
			  return pThisExpression;
		  }
	  }


	  public static Expression<Func<T, bool>> AndIfNotNullOrEmpty<T,O>(this Expression<Func<T, bool>> pThisExpression,
														   Expression<Func<T, bool>> pExpA, List<O> pValues)
	  {
		  if (!DataHelper.IsEmpty(pValues))
		  {
			  return And<T>(pThisExpression, pExpA, true);
		  }
		  else
		  {
			  return pThisExpression;
		  }
	  }


	  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> pThisExpression,
														  Expression<Func<T, bool>> pExpA, bool pAdd)
	  {
		if (pAdd)
		{		
			var invokedExpr = Expression.Invoke (pExpA, pThisExpression.Parameters.Cast<Expression> ());
			return Expression.Lambda<Func<T, bool>>
				  (Expression.OrElse (pThisExpression.Body, invokedExpr), pThisExpression.Parameters);
		}
		else
		{
			return pThisExpression;
		}
	  }
 
	  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> pThisExpression,
														   Expression<Func<T, bool>> pExpA, bool pAdd)
	  {
		if (pAdd)
		{
			var invokedExpr = Expression.Invoke (pExpA, pThisExpression.Parameters.Cast<Expression> ());
			return Expression.Lambda<Func<T, bool>>
				  (Expression.AndAlso (pThisExpression.Body, invokedExpr), pThisExpression.Parameters);
		}
		else
		{
			return pThisExpression;
		}
	  }


		public static Expression<Func<T, bool>> OrNullable<T,O> (this Expression<Func<T, bool>> pThisExpression,
															  Expression<Func<T, bool>> pExpNull, Expression<Func<T, bool>> pExpNotNull, Nullable<O> pValue) where O : struct
		{
			if (pValue == null)
			{
				return Or (pThisExpression, pExpNull);
			}
			else
			{
				return Or (pThisExpression, pExpNotNull);
			}
		}

		public static Expression<Func<T, bool>> AndNullable<T,O> (this Expression<Func<T, bool>> pThisExpression,
														   Expression<Func<T, bool>> pExpNull, Expression<Func<T, bool>> pExpNotNull, Nullable<O> pValue) where O : struct
		{
			if (pValue == null)
			{
				return And (pThisExpression, pExpNull);
			}
			else
			{
				return And (pThisExpression, pExpNotNull);
			}
		}
	}
}